'''
Created on Dec 21, 2011

@author: Victor Bos
'''

class Action:

    def undo(self):
        pass
    
    def redo(self):
        pass

class RenameTurnAction(Action):
    
    def __init__(self, oldturnname, newturnname):
        self.oldturnname = oldturnname
        self.newturnname = newturnname
        
    def undo(self, root):
        root.set_conf_name(self.oldturnname)
    
    def redo(self, root):
        root.set_conf_name(self.newturnname)

class NewTurnAction(RenameTurnAction):    
        pass

class ReplaceMapAction(Action):
    def __init__(self, old_filename, old_bytes, new_filename, new_bytes):
        self.old_filename = old_filename
        self.old_bytes = old_bytes
        self.new_filename = new_filename
        self.new_bytes = new_bytes

    def replace_map(self, root, filename, map_bytes):
        root.push_cursor("watch")
        root.undraw_map()
        root.gameconf.set_map_filename(filename)
        root.gameconf.mem_load_map(map_bytes)
        root.draw_map()
        root.pop_cursor()
        
    def undo(self, root):
        self.replace_map(root, self.old_filename, self.old_bytes)

    def redo(self, root):
        self.replace_map(root, self.new_filename, self.new_bytes)

class DefineNextAreaPointAction(Action):
    
    def __init__(self, point):
        self.point = point
        
    def undo(self, root):
        del root.cur_poly[-1]
        root.undraw_poly()
        root.draw_poly()
        root.center_view_on_point(self.point[0], self.point[1])
        
    def redo(self, root):
        root.cur_poly.append(self.point)
        root.undraw_poly()
        root.draw_poly()
        root.center_view_on_point(self.point[0], self.point[1])
        
class DefineLastAreaPointAction(Action):
    def __init__(self, area, neighbours):
        self.area = area
        self.neighbours = neighbours
        
    def undo(self, root):
        points = self.area.polygon
        root.remove_area(self.area.name)
        root.set_current_item_cid(None)
        root.start_new_poly(points)
        root.center_view_on_point(points[-1][0], points[-1][1])
        
    def redo(self, root):
        root.undraw_poly()
        root.add_area(self.area, self.neighbours)
        root.select_area_cid(root.area_cid[self.area.name])
        root.start_new_poly([])
        root.center_view_on_area(self.area)
        
class RemoveAreaAction(Action):

    def __init__(self, area, neighbours):
        self.area = area
        self.neighbours = neighbours
        
    def undo(self, root):
        root.add_area(self.area, self.neighbours)
        root.select_area_cid(root.area_cid[self.area.name])
        root.center_view_on_area(self.area)
        root.correct_z_order()
        
    def redo(self, root):
        root.center_view_on_area(self.area)
        root.remove_area(self.area.name)
        
class ChangeAreaAction(Action):
    
    def __init__(self, oldarea, newarea, neighbours):
        self.oldarea = oldarea
        self.newarea = newarea
        self.neighbours = neighbours

    def replace_area(self, root, a1, a2):
        root.remove_area(a1.name)
        root.add_area(a2, self.neighbours)
        root.select_area_cid(root.area_cid[a2.name])
        root.center_view_on_area(a2)
        root.correct_z_order()
                
    def undo(self, root):
        self.replace_area(root, self.newarea, self.oldarea)

    def redo(self, root):
        self.replace_area(root, self.oldarea, self.newarea)
    
class ColourAreaAction(Action):
    
    def __init__(self, x, y, oldcolour, newcolour):
        self.x = x
        self.y = y
        self.oldcolour = oldcolour
        self.newcolour = newcolour
    
    def change_area_colour(self, root, newcolour):
        root.push_cursor("watch")
        root.map_canvas.update_idletasks()
        root.fill_photoimage_area(
            root.game_map_tk, self.x, self.y, newcolour)# root.rgb256_colour(colour)
        root.pop_cursor()
        
    def undo(self, root):
        self.change_area_colour(root, self.oldcolour)

    def redo(self, root):
        self.change_area_colour(root, self.newcolour)
        
class DeleteUnitTypeAction(Action):
    def __init__(self, utp):
        self.utp = utp
        
    def undo(self, root):
        root.add_unit_type(self.utp)
        root.make_unit_type_buttons()
        root.select_unit_type()
        
    def redo(self, root):
        root.delete_unit_type(self.utp)
        root.make_unit_type_buttons()

class ChangeUnitTypeAction(Action):
    def __init__(self, oldutp, newutp):
        self.oldutp = oldutp
        self.newutp = newutp
        
    def replaceUnitType(self, root, utpa, utpb):
        if utpa.name != utpb.name:
            root.delete_unit_type(utpa)
        root.add_unit_type(utpb)
        root.make_unit_type_buttons()
        root.select_unit_type()
        
    def undo(self, root):
        self.replaceUnitType(root, self.newutp, self.oldutp)
        
    def redo(self, root):
        self.replaceUnitType(root, self.oldutp, self.newutp)
        
class DeleteUnitAction(Action):
    def __init__(self, unit):
        self.unit = unit
        self.moves = unit.get_move_dests()
        
    def undo(self, root):
        if len(self.moves)>0:
            self.unit.set_move_dests(self.moves)
        else:
            root.add_unit(self.unit)
        root.draw_unit(self.unit)
        root.center_view_on_unit(self.unit)
        root.set_current_item_cid(root.unit_cid(self.unit))
        
    def redo(self, root):
        root.center_view_on_unit(self.unit)
        root.unset_current_item_cid()
        if self.unit.nr_move_dests()>0:
            root.delete_move(self.unit)
            root.set_current_item_cid(root.unit_cid(self.unit))
        else:
            root.delete_unit(self.unit)

class ChangeUnitAction(Action):
    def __init__(self, gameunit, oldunit, newunit):
        self.gameunit = gameunit
        self.oldunit = oldunit
        self.newunit = newunit

    def replace_unit_attrs(self, root, gameunit, unit):
        root.undraw_unit(gameunit)
        gameunit.update(unit)
        root.reset_tk_bitmap(unit)
        root.draw_unit(gameunit)
        root.center_view_on_unit(gameunit)
        root.set_current_item_cid(root.unit_cid(gameunit))
        
    def undo(self, root):
        self.replace_unit_attrs(root, self.gameunit, self.oldunit)
        
    def redo(self, root):
        self.replace_unit_attrs(root, self.gameunit, self.newunit)

class ColourUnitAction(Action):
    def __init__(self, uname, oldcolourpair, newcolourpair):
        self.uname = uname
        self.oldcolourpair = oldcolourpair
        self.newcolourpair = newcolourpair
        
    def set_unit_colours(self, root, fg, bg):
        unit = root.gameconf.units[self.uname]
        unit.colour = fg
        unit.bgcolour = bg
        unit.xbm.configure(foreground=fg, background=bg)
        #root.draw_unit(unit)
        root.set_current_item_cid(root.unit_cid(unit))
        root.center_view_on_unit(unit)
        root.refresh_report()

    def undo(self, root):
        fg, bg = self.oldcolourpair
        self.set_unit_colours(root, fg, bg)
        
    def redo(self, root):
        fg, bg = self.newcolourpair
        self.set_unit_colours(root, fg, bg)
        
class MoveUnitToPrevLocAction(Action):
    def __init__(self, uname, last_x, last_y):
        self.uname = uname
        self.last_x = last_x
        self.last_y = last_y
        
    def undo(self, root):
        unit = root.gameconf.units[self.uname]
        root.undraw_unit(unit)
        unit.add_move_dest(self.last_x, self.last_y)
        root.draw_unit(unit)
        root.set_current_item_cid(root.unit_cid(unit))
        root.center_view_on_unit(unit)
        root.refresh_report()

    def redo(self, root):
        unit = root.gameconf.units[self.uname]
        root.undraw_unit(unit)
        unit.delete_last_move_dest(1)
        root.draw_unit(unit)
        root.set_current_item_cid(root.unit_cid(unit))
        root.center_view_on_unit(unit)
        root.refresh_report()

class MoveUnitAction(Action):
    def __init__(self, uname, old_x, old_y, new_x, new_y):
        self.uname = uname
        self.old_x = old_x
        self.old_y = old_y
        self.new_x = new_x
        self.new_y = new_y

    def do_move(self, x, y, root):
        unit = root.gameconf.units[self.uname]
        root.undraw_unit(unit)
        unit.set_last_move_xy(x, y)
        root.draw_unit(unit)
        root.set_current_item_cid(root.unit_cid(unit))
        root.center_view_on_unit(unit)
        root.refresh_report()

    def undo(self, root):
        self.do_move(self.old_x, self.old_y, root)

    def redo(self, root):
        self.do_move(self.new_x, self.new_y, root)

class MoveUnitNewDestAction(Action):
    def __init__(self, uname, new_x, new_y):
        self.uname = uname
        self.new_x = new_x
        self.new_y = new_y

    def undo(self, root):
        unit = root.gameconf.units[self.uname]
        root.undraw_unit(unit)
        unit.delete_last_move_dest(1)
        root.draw_unit(unit)
        root.set_current_item_cid(root.unit_cid(unit))
        root.center_view_on_unit(unit)
        root.refresh_report()

    def redo(self, root):
        unit = root.gameconf.units[self.uname]
        root.undraw_unit(unit)
        unit.add_move_dest(self.new_x, self.new_y)
        root.draw_unit(unit)
        root.set_current_item_cid(root.unit_cid(unit))
        root.center_view_on_unit(unit)
        root.refresh_report()

class AddUnitsAction(Action):
    def __init__(self, units):
        self.units = units
        
    def undo(self, root):
        if len(self.units)>0:
            root.center_view_on_unit(self.units[-1])
            root.delete_units(self.units)
    
    def redo(self, root):
        if len(self.units)>0:
            root.add_units(self.units)
            root.center_view_on_unit(self.units[-1])
        
class CommitUnitsAction(Action):
    def __init__(self, unames_moves):
        self.unames_moves = unames_moves# dict with (uname, move_dests) key-values

    def undo(self, root):
        uname0 = None
        for uname in self.unames_moves.keys():
            uname0 = uname
            u = root.gameconf.units[uname]
            root.undraw_unit(u)
            x, y = self.unames_moves[uname][0]
            move_dests = self.unames_moves[uname][1:]
            u.set_xy(x, y)
            u.set_move_dests(move_dests)
            root.draw_unit(u)
        if uname0 is not None:
            root.center_view_on_unit(root.gameconf.units[uname0])
        root.refresh_report()

    def redo(self, root):
        uname0 = None
        for uname in self.unames_moves.keys():
            uname0 = uname
            u = root.gameconf.units[uname]
            root.undraw_unit(u)
            u.execute_move()
            root.draw_unit(u)
        if uname0 is not None:
            root.center_view_on_unit(root.gameconf.units[uname0])
        root.refresh_report()

class AddColourPairAction(Action):
    def __init__(self, oldcolourpair, newcolourpair):
        self.oldcolourpair = oldcolourpair
        self.newcolourpair = newcolourpair
        
    def undo(self, root):
        del root.gameconf.colours[-1]
        root.make_colour_buttons()
        fg, bg = self.oldcolourpair
        root.set_current_colour(fg, bg)
        root.update_setup_editor()
        
    def redo(self, root):
        root.gameconf.colours.append(self.newcolourpair)
        root.make_colour_buttons()
        fg, bg = self.newcolourpair
        root.set_current_colour(fg, bg)
        root.update_setup_editor()
        
class DeleteColourPairAction(Action):
    def __init__(self, index, colourpair):
        self.index = index
        self.colourpair = colourpair
        
    def undo(self, root):
        root.gameconf.colours.insert(self.index, self.colourpair)
        root.make_colour_buttons()
        fg, bg = self.colourpair
        root.set_current_colour(fg, bg)
        root.update_setup_editor()
        
    def redo(self, root):
        del root.gameconf.colours[self.index]
        root.make_colour_buttons()
        i = -1
        if len(root.gameconf.colours) > 0:
            i = self.index - 1
            if i<0:
                i = 0
            fg, bg = root.gameconf.colours[i]
            root.set_current_colour(fg, bg)
        root.update_setup_editor()
        
class ChangeColourPairAction(Action):
    def __init__(self, oldcolourpair, newcolourpair):
        self.oldcolourpair = oldcolourpair
        self.newcolourpair = newcolourpair
        
    def change_colours(self, root, oldcp, newcp):
        i = root.gameconf.colours.index(oldcp)
        root.gameconf.colours[i] = newcp
        root.make_colour_buttons()
        fg, bg = newcp
        root.set_current_colour(fg, bg)
        root.update_setup_editor()

    def undo(self, root):
        self.change_colours(root, self.newcolourpair, self.oldcolourpair)

    def redo(self, root):
        self.change_colours(root, self.oldcolourpair, self.newcolourpair)
        